import JSZip from 'jszip';
import xmlFormatter from 'xml-formatter';
import { downloadFile, sleep } from '../../common';
import lyricsIcon from '../assets/icons/lyrics.svg?raw';
import { createMenuItem, onAlbumMenu, showMenuItem } from '../glue/ui/menu';
import { getAlbum } from '../services/album';
import { getLyrics } from '../services/lyrics';
import { Lyrics, Track } from '../types';

onAlbumMenu((menuEl, albumId) => {
	const downloadLyricsButtonEl = createMenuItem('Rip lyrics<br><small>* Requires a valid subscription<br>in the active storefront.</small>', lyricsIcon, true);

	downloadLyricsButtonEl.addEventListener('click', async () => {
		await ripLyrics(albumId);
	});

	showMenuItem(menuEl, downloadLyricsButtonEl);
});

async function ripLyrics(albumId: string) {
	const album = await getAlbum(albumId);
	if (!album) return;

	const zip = new JSZip();

	for (const track of album.relationships.tracks.data) {
		if (track.attributes.hasTimeSyncedLyrics) {
			const syllableLyrics = await getLyrics(track.id, true);
			if (syllableLyrics) zipLyrics(zip, track.attributes, syllableLyrics.attributes, true);
		}

		if (track.attributes.hasLyrics) {
			const lyrics = await getLyrics(track.id, false);
			if (lyrics) zipLyrics(zip, track.attributes, lyrics.attributes, false);
		}

		await sleep(100);
	}

	if (!Object.keys(zip.files).length) {
		alert('No lyrics could be downloaded.');
		return;
	}

	downloadFile(await zip.generateAsync({ type: 'blob' }), `[LYRICS] [${album.id}] ${album.attributes.artistName.slice(0, 80).trim()} - ${album.attributes.name.slice(0, 80).trim()}.zip`);
}

function zipLyrics(zip: JSZip, track: Track, lyrics: Lyrics, syllable: boolean) {
	const filename = `${track.discNumber}-${track.trackNumber.toString().padStart(2, '0')}. ${track.name.slice(0, 120).trim()}`;

	// Save raw lyrics.
	if (syllable && lyrics.ttml.includes('<span begin=')) {
		zip.file(`${filename}.syllable.ttml`, xmlFormatter(lyrics.ttml, { lineSeparator: '\n', indentation: '\t' }));
	} else {
		zip.file(`${filename}.ttml`, xmlFormatter(lyrics.ttml, { lineSeparator: '\n', indentation: '\t' }));
	}

	// Save converted lyrics.
	if (!syllable) {
		const lyricsDoc = new DOMParser().parseFromString(lyrics.ttml, 'text/xml');
		let out = '';

		for (const lineNode of Array.from(lyricsDoc.querySelectorAll('p')) as HTMLParagraphElement[]) {
			const timestamp = lineNode.getAttribute('begin');
			if (timestamp) {
				out += `[${convertTimestamp(timestamp)}] ${lineNode.textContent}\n`;
			} else {
				out += `${lineNode.textContent}\n`;
			}
		}

		zip.file(`${filename}.lrc`, out);
	}
}

function convertTimestamp(timestamp: string) {
	const parts = timestamp.split(/[:.]/g).reverse();
	const mm = (parts[2] ?? '').padStart(2, '0');
	const ss = (parts[1] ?? '').padStart(2, '0');
	const xx = Math.floor(Number(parts[0]) / 10).toString().padStart(2, '0');
	return `${mm}:${ss}.${xx}`;
}
